package ar.edu.unicen.exa.isistan.archassis.ia;

import java.util.ArrayList;
import java.util.List;

import ar.edu.unicen.exa.isistan.archassis.ia.api.db.JavaClass;
import ar.edu.unicen.exa.isistan.archassis.ia.api.db.ListCases;
import ar.edu.unicen.exa.isistan.archassis.ia.seed.ImplementsSeed;
import ar.edu.unicen.exa.isistan.archassis.ia.seed.MetodoSeed;
import ar.edu.unicen.exa.isistan.archassis.ia.seed.Run;
import ar.edu.unicen.exa.isistan.archassis.ia.seed.VariableSeed;

public class Result {

	private JavaClass inputJavaClass;
	private JavaClass caseJavaClass;
	private float cumplido;
	private float sobra;
	private ArrayList<String> listImplementsShared;
	private ArrayList<String> listImplementsCase;
	private ArrayList<String> listImplementsClass;
	private ArrayList<VariableSeed> listVarShared;
	private ArrayList<VariableSeed> listVarCase;
	private ArrayList<VariableSeed> listVarClass;
	private ArrayList<Run> listRunShared;
	private ArrayList<Run> listRunCase;
	private ArrayList<Run> listRunClass;
	private ListCases caso;
	private ArrayList<MetodoSeed> listMetodoShared;
	private ArrayList<MetodoSeed> listMetodoCase;
	private ArrayList<MetodoSeed> listMetodoClass;

	
	public Result(JavaClass inputJavaClass, JavaClass caseJavaClass, ListCases caseSeedList, float cumplido, float sobra){
		this.cumplido = cumplido;
		this.sobra = sobra;
		this.inputJavaClass = inputJavaClass;
		this.caseJavaClass = caseJavaClass;
		this.caso = caseSeedList;
	}
	
	public Result(JavaClass resultClass, JavaClass seed, ListCases caseSeedList){
		this(resultClass, seed, caseSeedList, 
				seed.eval(resultClass), 		//calculo y llamo al otro creador 
				(1f) -resultClass.eval(seed) 	//calculo y llamo al otro creador
			);
	}
	

	
	public JavaClass getResultClass() {
		return inputJavaClass;
	}
	public JavaClass getSeed() {
		return caseJavaClass;
	}

	public float getCumplido() {
		return cumplido;
	}

	public float getSobra() {
		return sobra;
	}
	
	


	public ListCases getCaso() {
		return caso;
	}

	private void loadVarList(){
		listVarShared = new ArrayList<VariableSeed>();
		listVarCase = new ArrayList<VariableSeed>();
		
		listVarClass = new ArrayList<VariableSeed>();
		if (inputJavaClass != null) {
			for (VariableSeed varClass : this.inputJavaClass.getVariables()){
				listVarClass.add(varClass);
			}
		}
		for (VariableSeed varSeed : this.caseJavaClass.getVariables()){
			if (this.inputJavaClass == null) {
				listVarCase.add(varSeed);
			} else if(this.inputJavaClass.getVariables().contains(varSeed)){
				//Si esta, comparten la, HECHOel implemeta variable
				listVarShared.add(varSeed);
				
				//Sobran 
				listVarClass.remove(varSeed);
			}else{
				//Si no esta en la variable, entonces es un FALTAN
				listVarCase.add(varSeed);
			}
		}
		
	}

	public List<VariableSeed> getVarShared() {
		if (listVarShared == null){
			this.loadVarList();
		}
		return listVarShared;
	}


	public List<VariableSeed> getVarClass() {
		if (listVarShared == null){
			this.loadVarList();
		}
		return listVarClass;
	}


	public List<VariableSeed> getVarCase() {
		if (listVarShared == null){
			this.loadVarList();
		}
		return listVarCase;
	}

	private void loadRunList(){
		listRunShared = new ArrayList<Run>();
		listRunCase = new ArrayList<Run>();
		
		listRunClass = new ArrayList<Run>();
		if (inputJavaClass != null) {
			for (MetodoSeed metClass : this.inputJavaClass.getMetodos()){
				for(Run run: metClass.getEjecuta()){
					listRunClass.add(run);
				}
			}
		}
		for (MetodoSeed metSeed : this.caseJavaClass.getMetodos()){
			if (this.inputJavaClass == null) {
				for(Run run: metSeed.getEjecuta()){
					listRunCase.add(run);
				}
			} else if(this.inputJavaClass.getMetodos().contains(metSeed)){
				//Si esta, comparten el ejecuta, HECHO el implemeta variable
				for(Run run: metSeed.getEjecuta()){
					listRunShared.add(run);
					//Sobran 
					listRunClass.remove(run);
				}
			}else{
				//Si no esta el metodo, entonces es un FALTAN
				for(Run run: metSeed.getEjecuta()){
					listRunCase.add(run);
					//Sobran 
				}
			}
		}
		
	}
	
	private void loadMetodoList(){
		listMetodoShared = new ArrayList<MetodoSeed>();
		listMetodoCase = new ArrayList<MetodoSeed>();
		
		listMetodoClass = new ArrayList<MetodoSeed>();
		if (inputJavaClass != null) {
			for (MetodoSeed metClass : this.inputJavaClass.getMetodos()){
				listMetodoClass.add(metClass);
			}
		}
		for (MetodoSeed metSeed : this.caseJavaClass.getMetodos()){
			if (this.inputJavaClass == null) {
				listMetodoCase.add(metSeed);
			} else if(this.inputJavaClass.getMetodos().contains(metSeed)){
				//Si esta, comparten el ejecuta, HECHO el implemeta variable
				listMetodoShared.add(metSeed);
					//Sobran 
				listMetodoClass.remove(metSeed);
			}else{
				//Si no esta el metodo, entonces es un FALTAN
				listMetodoCase.add(metSeed);
				//Sobran 
			}
		}
		
	}
	
	
	public ArrayList<MetodoSeed> getListMetodoShared() {
		if(listMetodoShared == null){
			this.loadMetodoList();
		}
		return listMetodoShared;
	}

	public ArrayList<MetodoSeed> getListMetodoCase() {
		if(listMetodoShared == null){
			this.loadMetodoList();
		}
		return listMetodoCase;
	}

	public ArrayList<MetodoSeed> getListMetodoClass() {
		if(listMetodoShared == null){
			this.loadMetodoList();
		}
		return listMetodoClass;
	}

	public List<Run> getRunShared() {
		if (listRunShared == null){
			this.loadRunList();
		}
		return listRunShared;
	}


	public List<Run> getRunClass() {
		if (listRunClass == null){
			this.loadRunList();
		}
		return listRunClass;
	}


	public List<Run> getRunCase() {
		if (listRunCase == null){
			this.loadRunList();
		}
		return listRunCase;
	}
	
	public String getExtendsCase() {
		return this.caseJavaClass.getEntiende();
	}
	
	public String getExtendsClass() {
		return this.inputJavaClass.getEntiende();
	}

	public boolean isExtendsEquals() {
		if (this.inputJavaClass == null) {
			return false;
		}
		return this.caseJavaClass.getEntiende().equals(this.inputJavaClass.getEntiende());
	}
	
	private void loadImplentsList(){
		listImplementsShared = new ArrayList<String>();
		listImplementsCase = new ArrayList<String>();
		
		listImplementsClass = new ArrayList<String>();
		
		if (inputJavaClass != null) {
			for (ImplementsSeed implClass : this.inputJavaClass.getImplementa()){
				listImplementsClass.add(implClass.getValor());
			}
		}
		
		for (ImplementsSeed implSeed : this.caseJavaClass.getImplementa()){
			if (this.inputJavaClass == null) {
				//es un FALTAN
				listImplementsCase.add(implSeed.getValor());
			} else if(this.inputJavaClass.getImplementa().contains(implSeed)){
				//Si esta, comparten el implemeta, HECHO
				listImplementsShared.add(implSeed.getValor());
				
				//Sobran 
				listImplementsClass.remove(implSeed.getValor());
			}else{
				//Si no esta en la clase, entonces es un FALTAN
				listImplementsCase.add(implSeed.getValor());
			}
		}
		
	}

	public List<String> getImplementsShared() {
		if (listImplementsShared == null){
			this.loadImplentsList();
		}
		return listImplementsShared;
	}


	public List<String> getImplementsCase() {
		if (listImplementsShared == null){
			this.loadImplentsList();
		}
		return listImplementsCase;
	}


	public List<String> getImplementsClass() {
		if (listImplementsShared == null){
			this.loadImplentsList();
		}
		return listImplementsClass;
	}
	
	public String getCaseName(){
		return caso.getName();
	}
	
	public Long getCaseId(){
		return caso.getId();
	}

	public boolean betterThan(Result r) {
		if (r == null) {
			//soy mejor que "null"
			return true;
		}
		
		if (r.getCumplido() < this.getCumplido()) {
			//mi "cumplido" es mejor que el suyo
			return true;
		}
		
		if (r.getCumplido() == this.getCumplido()) {
			//los cumplidos son iguales
			if (r.getSobra() > this.getSobra()) {
				//mi sobras son menores
				return true;
			}
		}
		return false;
	}

	
}
